{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n********************************\nCreating Colormaps in Matplotlib\n********************************\n\nMatplotlib has a number of built-in colormaps accessible via\n`.matplotlib.cm.get_cmap`.  There are also external libraries like\npalettable_ that have many extra colormaps.\n\n\nHowever, we often want to create or manipulate colormaps in Matplotlib.\nThis can be done using the class `.ListedColormap` and a Nx4 numpy array of\nvalues between 0 and 1 to represent the RGBA values of the colormap.  There\nis also a `.LinearSegmentedColormap` class that allows colormaps to be\nspecified with a few anchor points defining segments, and linearly\ninterpolating between the anchor points.\n\nGetting colormaps and accessing their values\n============================================\n\nFirst, getting a named colormap, most of which are listed in\n:doc:`/tutorials/colors/colormaps` requires the use of\n`.matplotlib.cm.get_cmap`, which returns a\n:class:`.matplotlib.colors.ListedColormap` object.  The second argument gives\nthe size of the list of colors used to define the colormap, and below we\nuse a modest value of 12 so there are not a lot of values to look at.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import numpy as np\nimport matplotlib.pyplot as plt\nfrom matplotlib import cm\nfrom matplotlib.colors import ListedColormap, LinearSegmentedColormap\n\nviridis = cm.get_cmap('viridis', 12)\nprint(viridis)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The object ``viridis`` is a callable, that when passed a float between\n0 and 1 returns an RGBA value from the colormap:\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(viridis(0.56))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The list of colors that comprise the colormap can be directly accessed using\nthe ``colors`` property,\nor it can be accessed indirectly by calling  ``viridis`` with an array\nof values matching the length of the colormap.  Note that the returned list\nis in the form of an RGBA Nx4 array, where N is the length of the colormap.\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print('viridis.colors', viridis.colors)\nprint('viridis(range(12))', viridis(range(12)))\nprint('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The colormap is a lookup table, so \"oversampling\" the colormap returns\nnearest-neighbor interpolation (note the repeated colors in the list below)\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print('viridis(np.linspace(0, 1, 15))', viridis(np.linspace(0, 1, 15)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Creating listed colormaps\n=========================\n\nThis is essential the inverse operation of the above where we supply a\nNx4 numpy array with all values between 0 and 1,\nto `.ListedColormap` to make a new colormap.  This means that\nany numpy operations that we can do on a Nx4 array make carpentry of\nnew colormaps from existing colormaps quite straight forward.\n\nSuppose we want to make the first 25 entries of a 256-length \"viridis\"\ncolormap pink for some reason:\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "viridis = cm.get_cmap('viridis', 256)\nnewcolors = viridis(np.linspace(0, 1, 256))\npink = np.array([248/256, 24/256, 148/256, 1])\nnewcolors[:25, :] = pink\nnewcmp = ListedColormap(newcolors)\n\n\ndef plot_examples(cms):\n    \"\"\"\n    helper function to plot two colormaps\n    \"\"\"\n    np.random.seed(19680801)\n    data = np.random.randn(30, 30)\n\n    fig, axs = plt.subplots(1, 2, figsize=(6, 3), constrained_layout=True)\n    for [ax, cmap] in zip(axs, cms):\n        psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4)\n        fig.colorbar(psm, ax=ax)\n    plt.show()\n\nplot_examples([viridis, newcmp])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can easily reduce the dynamic range of a colormap; here we choose the\nmiddle 0.5 of the colormap.  However, we need to interpolate from a larger\ncolormap, otherwise the new colormap will have repeated values.\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "viridisBig = cm.get_cmap('viridis', 512)\nnewcmp = ListedColormap(viridisBig(np.linspace(0.25, 0.75, 256)))\nplot_examples([viridis, newcmp])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "and we can easily concatenate two colormaps:\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "top = cm.get_cmap('Oranges_r', 128)\nbottom = cm.get_cmap('Blues', 128)\n\nnewcolors = np.vstack((top(np.linspace(0, 1, 128)),\n                       bottom(np.linspace(0, 1, 128))))\nnewcmp = ListedColormap(newcolors, name='OrangeBlue')\nplot_examples([viridis, newcmp])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Of course we need not start from a named colormap, we just need to create\nthe Nx4 array to pass to `.ListedColormap`.  Here we  create a\nbrown colormap that goes to white....\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "N = 256\nvals = np.ones((N, 4))\nvals[:, 0] = np.linspace(90/256, 1, N)\nvals[:, 1] = np.linspace(39/256, 1, N)\nvals[:, 2] = np.linspace(41/256, 1, N)\nnewcmp = ListedColormap(vals)\nplot_examples([viridis, newcmp])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Creating linear segmented colormaps\n===================================\n\n`.LinearSegmentedColormap` class specifies colormaps using anchor points\nbetween which RGB(A) values are interpolated.\n\nThe format to specify these colormaps allows discontinuities at the anchor\npoints. Each anchor point is specified as a row in a matrix of the\nform ``[x[i] yleft[i] yright[i]]``, where ``x[i]`` is the anchor, and\n``yleft[i]`` and ``yright[i]`` are the values of the color on either\nside of the anchor point.\n\nIf there are no discontinuities, then ``yleft[i]=yright[i]``:\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cdict = {'red':   [[0.0,  0.0, 0.0],\n                   [0.5,  1.0, 1.0],\n                   [1.0,  1.0, 1.0]],\n         'green': [[0.0,  0.0, 0.0],\n                   [0.25, 0.0, 0.0],\n                   [0.75, 1.0, 1.0],\n                   [1.0,  1.0, 1.0]],\n         'blue':  [[0.0,  0.0, 0.0],\n                   [0.5,  0.0, 0.0],\n                   [1.0,  1.0, 1.0]]}\n\n\ndef plot_linearmap(cdict):\n    newcmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256)\n    rgba = newcmp(np.linspace(0, 1, 256))\n    fig, ax = plt.subplots(figsize=(4, 3), constrained_layout=True)\n    col = ['r', 'g', 'b']\n    for xx in [0.25, 0.5, 0.75]:\n        ax.axvline(xx, color='0.7', linestyle='--')\n    for i in range(3):\n        ax.plot(np.arange(256)/256, rgba[:, i], color=col[i])\n    ax.set_xlabel('index')\n    ax.set_ylabel('RGB')\n    plt.show()\n\nplot_linearmap(cdict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In order to make a discontinuity at an anchor point, the third column is\ndifferent than the second.  The matrix for each of \"red\", \"green\", \"blue\",\nand optionally \"alpha\" is set up as::\n\n  cdict['red'] = [...\n                  [x[i]      yleft[i]     yright[i]],\n                  [x[i+1]    yleft[i+1]   yright[i+1]],\n                 ...]\n\nand for values passed to the colormap between ``x[i]`` and ``x[i+1]``,\nthe interpolation is between ``yright[i]`` and ``yleft[i+1]``.\n\nIn the example below there is a discontinuity in red at 0.5.  The\ninterpolation between 0 and 0.5 goes from 0.3 to 1, and between 0.5 and 1\nit goes from 0.9 to 1.  Note that red[0, 1], and red[2, 2] are both\nsuperfluous to the interpolation because red[0, 1] is the value to the\nleft of 0, and red[2, 2] is the value to the right of 1.0.\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cdict['red'] = [[0.0,  0.0, 0.3],\n                [0.5,  1.0, 0.9],\n                [1.0,  1.0, 1.0]]\nplot_linearmap(cdict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "------------\n\nReferences\n\"\"\"\"\"\"\"\"\"\"\n\nThe use of the following functions, methods, classes and modules is shown\nin this example:\n\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "import matplotlib\nmatplotlib.axes.Axes.pcolormesh\nmatplotlib.figure.Figure.colorbar\nmatplotlib.colors\nmatplotlib.colors.LinearSegmentedColormap\nmatplotlib.colors.ListedColormap\nmatplotlib.cm\nmatplotlib.cm.get_cmap"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
